# 在绑定属性时，如果我们直接把属性暴露出去，虽然写起来很简单，但是，没办法检查参数，导致可以把数据随便改：

# 好处把一个getter方法变成属性，只需要加上@property就可以了，此时，@property本身又创建了另一个装饰器@score.setter，

class Student(object):

    def get_score(self):
        return self._score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value


s = Student()
s.set_score(90)
print(s.get_score())
print('***********限制了*******************')
# 现在，对任意的Student实例进行操作，就不能随心所欲地设置score了：
# print(s.set_score('0'))
# print(s.set_score(105))
print('***********@property*******************')


# Python内置的@property装饰器就是负责把一个方法变成属性调用
# 有没有既能检查参数，又可以用类似属性这样简单的方式来访问类的变量
class Student2(object):
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value


s2 = Student2()
s2.score = 90
print(s2.score)
# s2.score = 9000
# print(s2.score)
# 把一个getter方法变成属性，只需要加上@property就可以了，此时，@property本身又创建了另一个装饰器@score.setter，
# 负责把一个setter方法变成属性赋值，于是，我们就拥有一个可控的属性操作
print('*****************************设置属性************************************')


# birth是可读写属性，而age就是一个只读属性，因为age可以根据birth和当前时间计算出来。
class Student3(object):
    @property
    def birth(self):
        return self._birth

    @birth.setter
    def birth(self, value):
        self._birth = value

    @property
    def age(self):
        return 2015 - self._birth


s3 = Student3()
s3.birth =1990
print(s3.age)